import type { LegacyRef } from 'react';
import React, { useRef } from 'react';
import css from './sheet.css';
// 属性类型
type PropField = {
  /** 表单数据 */
  sheet: API.Sheet;
  /** 颜色列表 */
  colors: Record<string, string>;
  /** 宽度调整系数 */
  widthrRatio: number;
  /** 高度调整系数 */
  heightRatio: number;
  /** 显示区域的高度 */
  offsetHeight: number;
  /** 滚动条的宽度 */
  scrollbarWidth: number;
  /** 是否在Tab中 */
  inTab: boolean;
};
const Sheet: React.FC<PropField> = (props) => {
  const dataDiv: LegacyRef<HTMLDivElement> = useRef(null);
  const headDiv: LegacyRef<HTMLDivElement> = useRef(null);
  const inRange = (row: number, col: number, range: API.Range | API.Range[]) => {
    if (!range) {
      return;
    }
    if (range instanceof Array) {
      for (let i = 0; i < range.length; i++) {
        if (
          row >= range[i].srow &&
          row <= range[i].erow &&
          col >= range[i].scol &&
          col <= range[i].ecol
        ) {
          return true;
        }
      }
    } else {
      if (row >= range.srow && row <= range.erow && col >= range.scol && col <= range.ecol) {
        return true;
      }
    }
    return false;
  };
  const toAlphaString = (value: number) => {
    if (value < 0) {
      return '';
    }
    let ans = '';
    let i = value;
    while (i > 0) {
      ans = String.fromCharCode(((i - 1) % 26) + 65) + ans;
      i = Math.floor((i - 1) / 26);
    }
    return ans;
  };
  const getTdRetract = (val: string) => {
    if (!val) {
      return 0;
    }
    let retract = 0;
    for (let i = 0; i < 100; i++) {
      if (val.charAt(i) === ' ') {
        retract = retract + 5;
      } else {
        break;
      }
    }
    return retract;
  };
  const scrollHandler = () => {
    if (!dataDiv || !dataDiv.current) {
      return;
    }
    if (!headDiv || !headDiv.current) {
      return;
    }
    headDiv.current.scrollLeft = dataDiv.current.scrollLeft;
  };
  const renderTR = (
    range: API.Range,
    cells: Record<string, string>,
    table: API.TableItem,
    tIndex: number,
  ) => {
    const { heightRatio, widthrRatio } = props;
    const { mergeCells, columnsWidth } = props.sheet;
    if (!range) {
      return [];
    }
    if (range.srow === 0 && range.erow === 0) {
      return [];
    }
    const trs = [];
    let cell = '';
    const rowSpans = {};
    const colSpans = {};
    let bgcolor = '';
    let fontSize = null;
    let textAlign: 'left' | 'right' | 'center' = 'left';
    let alph = null;
    const colStart = table.rowRange.ecol + 1;
    for (let i = range.srow; i <= range.erow; i++) {
      const tds = [];
      for (let j = range.scol; j <= range.ecol; j++) {
        if (colSpans[i] > 1) {
          colSpans[i]--;
          continue;
        }
        if (rowSpans[j] > 1) {
          rowSpans[j]--;
          continue;
        }
        alph = toAlphaString(j);
        cell = alph + i;
        fontSize = null;
        bgcolor = 'white';
        textAlign = 'left';
        if (cell === table.title) {
          fontSize = 18;
        } else if (alph === table.rowNoCol) {
          textAlign = 'center';
        } else if (inRange(i, j, table.formulaCells)) {
          bgcolor = props.colors.formula;
        } else if (inRange(i, j, table.unusedCells)) {
          bgcolor = props.colors.noUse;
        }
        if (i <= table.columnRange.erow) {
          textAlign = 'center';
        } else if (j >= colStart) {
          textAlign = 'right';
        }
        let fixStyle = {};
        if (i > table.columnRange.erow && i <= table.dataRange.erow && j < colStart) {
          let left = 0;
          for (let k = 1; k <= j - 1; k++) {
            left += columnsWidth[k] * widthrRatio;
          }
          fixStyle = { position: 'sticky', left: `${left}px`, zIndex: 7, display: 'table-cell' };
        }
        if (mergeCells[cell]) {
          const rs = mergeCells[cell].rowspan;
          const cs = mergeCells[cell].colspan;
          for (let k = 0; k < cs; k++) {
            rowSpans[k + j] = rs;
          }
          for (let k = 0; k < rs; k++) {
            colSpans[k + i] = cs;
          }
          const tdstyle = {
            fontSize: fontSize!,
            backgroundColor: bgcolor,
            textAlign: textAlign,
            paddingLeft: 3,
            paddingRight: 3,
            ...fixStyle,
          };
          const tdorth =
            i <= table.columnRange.erow ? (
              <th key={cell} colSpan={colSpans[i]} rowSpan={rowSpans[j]} style={tdstyle}>
                {mergeCells[cell].value}
              </th>
            ) : (
              <td key={cell} colSpan={colSpans[i]} rowSpan={rowSpans[j]} style={tdstyle}>
                {mergeCells[cell].value}
              </td>
            );
          tds.push(tdorth);
          continue;
        }
        const padding = 3;
        const val = cells[cell];
        let retract = 3;
        const captionCol = table.rowRange.ecol;
        if (j === captionCol) {
          retract += getTdRetract(cells[cell]);
        }
        const tdstyle = {
          fontSize: fontSize!,
          backgroundColor: bgcolor,
          textAlign: textAlign,
          paddingLeft: retract,
          paddingRight: padding,
          ...fixStyle,
        };
        const tdorth =
          i <= table.columnRange.erow ? (
            <th key={cell} style={tdstyle}>
              {val}
            </th>
          ) : (
            <td key={cell} style={tdstyle}>
              {val}
            </td>
          );
        tds.push(tdorth);
      }
      if (i === 1) {
        tds.push(<th key="lastbar" rowSpan={table.columnRange.erow} style={{ border: 'none' }} />);
      }
      trs.push(
        <tr
          key={'' + tIndex + '_' + i}
          style={{ height: '' + table.rowHeights[i] * heightRatio + 'pt' }}
        >
          {tds}
        </tr>,
      );
    }
    return trs;
  };
  const renderTable = (tableItem: API.TableItem, i: number) => {
    const {
      headRange,
      columnRange,
      dataRange,
      tailRange,
      rowHeights,
      columnCells,
      headCells,
      dataCells,
      tailCells,
    } = tableItem;
    const headTrs = renderTR(headRange, headCells, tableItem, i);
    const columnTrs = renderTR(columnRange, columnCells, tableItem, i);
    const dataTrs = renderTR(dataRange, dataCells, tableItem, i);
    const tailTrs = renderTR(tailRange, tailCells, tableItem, i);
    const { columnsWidth, width } = props.sheet;
    const colLen = Object.keys(columnsWidth).length;
    const colTds = [];
    for (let k = 1; k <= colLen; k++) {
      colTds.push(
        <col key={k} style={{ width: '' + columnsWidth[k] * props.widthrRatio + 'px' }} />,
      );
    }
    const colTds2 = [
      ...colTds,
      <col key={colLen + 1} style={{ width: '' + props.scrollbarWidth + 'px' }} />,
    ];
    let headHeigth = 0;
    for (let k = 1; k <= columnRange.erow; k++) {
      headHeigth += rowHeights[k] * props.heightRatio;
    }
    const tabHeigth = props.offsetHeight - headHeigth;
    return (
      <div key="excelRept" className={props.inTab ? css.container2_div : css.container_div}>
        <div key="head" ref={i === 0 ? headDiv : null} className={css.rowHead_div}>
          <table
            cellSpacing="0"
            cellPadding="0"
            className={css.data_table}
            width={'' + width * props.widthrRatio + props.scrollbarWidth + 'px'}
            style={{ borderCollapse: 'separate', borderSpacing: 0 }}
          >
            <colgroup>{colTds2}</colgroup>
            <thead key={i}>
              {headTrs}
              {columnTrs}
            </thead>
          </table>
        </div>
        <div
          key="data"
          ref={i === 0 ? dataDiv : null}
          className={css.data_div}
          style={{ height: tabHeigth }}
          onScroll={() => scrollHandler()}
        >
          <table
            cellSpacing="0"
            cellPadding="0"
            className={css.data_table}
            width={'' + width * props.widthrRatio + 'px'}
            style={{ borderCollapse: 'separate', borderSpacing: 0 }}
          >
            <colgroup>{colTds}</colgroup>
            <tbody key={i}>
              {dataTrs}
              {tailTrs}
            </tbody>
          </table>
        </div>
      </div>
    );
  };
  const { columnsWidth } = props.sheet;
  if (!columnsWidth) {
    return <></>;
  }
  const tbodys = props.sheet.tableItems.map((item, i) => renderTable(item, i));
  return <>{tbodys}</>;
};
export default Sheet;
